/*
 * $Id: UserDetailsServiceImpl.java 42 2013-04-17 15:33:59Z gabakyan $
 * $Author: gabakyan $
 * $Revision: 42 $
 * $Date: 2013-04-17 15:33:59 +0000 (Wed, 17 Apr 2013) $
 *
 * Copyright (c) 2013 Supply Chain Intelligence (SCI), Inc.
 * http://www.scintelligence.com/, Email: info@scintelligence.com
 * All rights reserved.
 *
 * This file is part of Logistics Map.
 *
 * Logistics Map is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * Logistics Map is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Logistics Map.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.sci.logisticsmap.web.security;

import com.sci.logisticsmap.service.model.OpenIDSignUpDTCommand;
import com.sci.logisticsmap.service.model.SessionUserDTModel;
import com.sci.logisticsmap.web.security.support.SecurityUtilities;
import com.sci.logisticsmap.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.openid.OpenIDAttribute;
import org.springframework.security.openid.OpenIDAuthenticationToken;

import java.util.*;

/**
 * The class {@code MyOpenIDAuthenticationProvider} represents the implementation of
 * {@link UserDetailsService} which loads the user-specific data and allows for retrieving a
 * UserDetails object based on an <code>Authentication</code> object.
 *
 * @author gabakyan@gmail.com (Last modified by $Author: gabakyan $)
 * @version $Revision: 42 $
 *
 * @see org.springframework.security.core.userdetails.UserDetailsService
 * @see org.springframework.security.core.userdetails.AuthenticationUserDetailsService
 */
//@Service
//@Transactional(readOnly = true)
public class UserDetailsServiceImpl implements UserDetailsService, AuthenticationUserDetailsService {
    /**
     * The logger.
     */
    private static final Logger logger;

    /**
     * The user service.
     */
    @Autowired
    private UserService userService;

    /**
     * The static initialization block.
     */
    static {
        logger = LoggerFactory.getLogger(UserDetailsServiceImpl.class);
    }

    /*
     * (non-Javadoc)
     *
     * @see UserDetailsService#loadUserByUsername(String)
     */
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SessionUserDTModel user = userService.getSessionUserDTModelByUsername(username);
        if (user != null) {
            logger.debug("User with username '{}' found!", username);
            return createUserDetails(user);
        } else {
            StringBuilder stringBuilder = new StringBuilder();
            logger.error("No user with username '{}' found!", username);
            throw new UsernameNotFoundException(stringBuilder.append("No user with username '").append(username).append("' found!").toString());
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see AuthenticationUserDetailsService#loadUserDetails(org.springframework.security.core.Authentication)
     */
    public UserDetails loadUserDetails(Authentication authentication) throws UsernameNotFoundException {
        OpenIDAuthenticationToken authenticationToken = (OpenIDAuthenticationToken) authentication;

        //String id = token.getIdentityUrl();
        String email = null;
        String firstName = null;
        String lastName = null;
        //String fullName = null;
        //String language = "";

        for (OpenIDAttribute attribute : authenticationToken.getAttributes()) {
            if (attribute.getName().equals("email")) {
                email = attribute.getValues().get(0);
            }
            if (attribute.getName().equals("firstName")) {
                firstName = attribute.getValues().get(0);
            }
            if (attribute.getName().equals("lastName")) {
                lastName = attribute.getValues().get(0);
            }
            /*if (attribute.getName().equals("fullname")) {
                fullName = attribute.getValues().get(0);
            }*/
            /*if (attribute.getName().equals("language")) {
                language = attribute.getValues().get(0);
            }*/
        }

        /*if (fullName == null) {
            StringBuilder fullNameBuilder = new StringBuilder();
            if (firstName != null) {
                fullNameBuilder.append(firstName);
            }
            if (lastName != null) {
                fullNameBuilder.append(" ").append(lastName);
            }
            fullName = fullNameBuilder.toString();
        }*/

        try {
            //SessionUserDTModel user = userService.getSessionUserByUsername(email);
            SessionUserDTModel user = userService.openIDSignUp(createOpenIDSignUpCommand(email, firstName, lastName));
            //logger.debug("User with username '{}' was signed up!", email);

            logger.debug("User with username '{}' found!", email);
            return createUserDetails(user);

            /*UserDetails userDetails = createUserDetails(email);

            OpenIDAuthenticationToken openIDAuthenticationToken = new OpenIDAuthenticationToken(userDetails, userDetails.getAuthorities(),
                    authenticationToken.getIdentityUrl(), authenticationToken.getAttributes());
            openIDAuthenticationToken.setAuthenticated(openIDAuthenticationToken.getStatus() == OpenIDAuthenticationStatus.SUCCESS);
            SecurityContextHolder.getContext().setAuthentication(openIDAuthenticationToken);

            return userDetails;*/
        } catch (Exception e) {
            StringBuilder stringBuilder = new StringBuilder();
            throw new UsernameNotFoundException(stringBuilder.append("No user with username '").append(email).append("' found!").toString());
        }
    }

    /**
     * Creates the user details.
     *
     * @param user The user.
     *
     * @return The user details.
     */
    private UserDetails createUserDetails(SessionUserDTModel user) {
        Collection<GrantedAuthority> authorities = SecurityUtilities.buildAuthorities(user.getRoles());
        return new UserDetailsImpl(user.getUsername(), user.getPassword(), authorities, user);
    }

    /**
     * Creates the OpenID sign up command.
     *
     * @param username The username.
     * @param firstName The first name.
     * @param lastName The last name.
     *
     * @return The OpenID sign up command.
     */
    private OpenIDSignUpDTCommand createOpenIDSignUpCommand(String username, String firstName, String lastName) {
        OpenIDSignUpDTCommand command = new OpenIDSignUpDTCommand();
        command.setUsername(username);
        command.setFirstName(firstName);
        command.setLastName(lastName);
        return command;
    }
}
